<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
namespace Mine\Exception\Handler;

use App\Common\Service\Tool\RouteService;
use Hyperf\Contract\StdoutLoggerInterface;
use Hyperf\ExceptionHandler\ExceptionHandler;
use Hyperf\HttpMessage\Stream\SwooleStream;
use Hyperf\Logger\LoggerFactory;
use Hyperf\Utils\Codec\Json;
use Mine\Event\ApiAfter;
use Mine\MineRequest;
use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\Http\Message\ResponseInterface;
use Hyperf\Logger\Logger;
use Throwable;

class AppExceptionHandler extends ExceptionHandler
{
    protected Logger $logger;

    /**
     * @var StdoutLoggerInterface
     */
    protected StdoutLoggerInterface $console;

    /**
     * @var MineRequest
     */
    protected MineRequest $request;

    /**
     * @var EventDispatcherInterface
     */
    protected EventDispatcherInterface $evDispatcher;

    public function __construct()
    {
        $this->console = console();
        $this->logger = container()->get(LoggerFactory::class)->get('mineAdmin');
        $this->request = make(MineRequest::class);
        $this->evDispatcher = make(EventDispatcherInterface::class);
    }

    public function handle(Throwable $throwable, ResponseInterface $response): ResponseInterface
    {
        $this->console->error(sprintf('%s[%s] in %s', $throwable->getMessage(), $throwable->getLine(), $throwable->getFile()));
        $this->console->error($throwable->getTraceAsString());
        $this->logger->error(sprintf('%s[%s] in %s', $throwable->getMessage(), $throwable->getLine(), $throwable->getFile()));
        $format = [
            'success' => false,
            'code'    => 500,
            'message' => $throwable->getMessage()
        ];

        // 记录api日志
        if (api()) {
            // 日志记录
            /** @var RouteService $rouceService */
            $rouceService = make(RouteService::class);
            $route = $rouceService->getControllerAndAction($this->request);
            $apiData = [
                'route' => $route,
                'error_message' => $throwable->getMessage() . ';' . $throwable->getFile() . ';第' . $throwable->getLine() . '行'
            ];
            $event = new ApiAfter(['apiData' => $apiData], $response);
            $this->evDispatcher->dispatch($event);
        }

        return $response->withHeader('Server', 'Grace')
            ->withAddedHeader('content-type', 'application/json; charset=utf-8')
            ->withStatus(500)->withBody(new SwooleStream(Json::encode($format)));
    }

    public function isValid(Throwable $throwable): bool
    {
        return true;
    }
}
